/*
 * Copyright (C) 2015 Daniel Uppenkamp
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.maurersmarbles;

import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 *
 * @author Daniel Uppenkamp
 */
public class CardDeck {

    /**
     * The number of cards in a full deck.
     */
    public static final int NUMBER_OF_CARDS_IN_FULL_DECK = 52;
    /**
     * The list of cards.
     */
    protected final List<Card> cards = new ArrayList();

    /**
     * Creates a new unshuffled CardDeck.
     */
    public CardDeck() {
        this(false);
    }

    /**
     * Creates a new CardDeck.
     *
     * @param shuffle whether or not to shuffle the deck
     */
    public CardDeck(boolean shuffle) {

        // add all of the cards to the undealt card list
        for (int cardId : Card.CARD_IDS) {
            for (char cardSuit : Card.CARD_SUITS) {
                if (cardId == Card.CARD_ID_4) {
                    cards.add(new Card(cardId, cardSuit, -4));
                }
                else {
                    cards.add(new Card(cardId, cardSuit));
                }
            }
        }

        if (shuffle) {
            shuffle();
        }

    }

    /**
     * Creates a new CardDeck, making a shallow copy of the cards.
     *
     * @param cardDeck the card deck to copy
     */
    public CardDeck(CardDeck cardDeck) {
        this(cardDeck, false);
    }

    /**
     * Creates a new CardDeck.
     *
     * @param cardDeck the card deck to copy
     * @param deepCopy whether or not to make a deep copy of the cards
     */
    public CardDeck(CardDeck cardDeck, boolean deepCopy) {

        Preconditions.checkNotNull(cardDeck, "Null card deck");

        if (deepCopy) {

            // make a deep copy of the cards
            for (Card card : cardDeck.cards) {
                this.cards.add(new Card(card));
            }

        }
        else {

            // make a shallow copy of the cards
            cards.addAll(cardDeck.cards);

        }

    }

    /**
     * Returns the next card in the card deck, or null if there aren't any more
     * cards.
     *
     * @return the next card in the card deck, or null if there aren't any more
     * cards
     */
    public Card nextCard() {
        if (isEmpty()) {
            return null;
        }
        return cards.remove(0);
    }

    /**
     * Returns whether or not the card deck is empty.
     *
     * @return whether or not the card deck is empty
     */
    public boolean isEmpty() {
        return cards.isEmpty();
    }

    /**
     * Returns whether or not the card deck is full (no cards dealt yet).
     *
     * @return whether or not the card deck is full (no cards dealt yet)
     */
    public boolean isFull() {
        return cards.size() == NUMBER_OF_CARDS_IN_FULL_DECK;
    }

    /**
     * Shuffles the cards in the deck.
     */
    public final void shuffle() {
        Collections.shuffle(cards);
    }

    @Override
    public String toString() {

        if (isEmpty()) {
            return "[]";
        }

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(cards.size()).append(" cards [");
        for (Card card : cards) {
            stringBuilder.append(card.toString()).append(", ");
        }
        stringBuilder.delete(stringBuilder.length() - 2, stringBuilder.length());
        stringBuilder.append("]");

        return stringBuilder.toString();

    }

}
